/** Easy parallelize job group manager.
 *
 *  Easy parallelize job group manager.
 *
 *  @author : huicong
 *  @date : 2008-11-03
 *
 */

#ifndef _EASY_PARALLEL_GROUP_MANAGER_H
#define _EASY_PARALLEL_GROUP_MANAGER_H

#include "BasicHeader.h"
#include <cstdio>
#include <set>
#include <vector>
#include <iostream>

namespace bcmi_frame
{

    class EasyParallelGroupManager
    {
    public:
        typedef std::set<UINT> GROUP_TYPE;
        typedef std::vector<GROUP_TYPE> GROUP_LIST;

    public:
        /** 
         *
         *  @param [IN] UINT _pNumber : number of process
         *
         */
        EasyParallelGroupManager(IN UINT _pNumber)
        {
            _processNumber = _pNumber;
            newArray(&_processGroupId, _processNumber);
            for (UINT i = 0; i < _processNumber; ++i)
            {
                _processGroupId[i] = EMPTY_GROUP_ID;
            }
        }

        ~EasyParallelGroupManager()
        {
            delete[] _processGroupId;
            _processGroupId = NULL;
        }

    public:

        /** Create a new process group
         * 
         *  @return : the number of all group N, the group id is N-1
         * 
         */
        UINT newGroup()
        {
            GROUP_TYPE _gp;
            _group.push_back(_gp);
            return _group.size();
        }

        /** Insert the _pid process into _gid group
         *
         *  NOTE : if the _pid or _gid not exits, or _pid is already in one group, do nothing and WORNING;
         *
         *  @param [IN] UINT _pid : id of process
         *  @param [IN] UINT _gid : id of group
         *
         */
        VOID insertGroup(IN UINT _pid, IN UINT _gid)
        {
            if (_pid < 0 || _pid >= _processNumber
                || _processGroupId[_pid] >= 0
                || _gid < 0 || _gid >= _group.size())
            {
#ifdef WARNING_EASY_PARALLEL_GROUP_MANAGER
                printf("Wrong %d process in wrong %d group", _pid, _gid);
#endif //#ifdef WORNING_EASY_PARALLEL_GROUP_MANAGER
            }

            _group[_gid].insert(_pid);
            _processGroupId[_pid] = _gid;
        }

        /** return group id of _pid process */
        UINT askGroup(IN UINT _pid)
        {
            return _processGroupId[_pid];
        }

        UINT processNumber()
        {
            return _processNumber;
        }

        UINT groupNumber()
        {
            return _group.size();
        }

        UINT groupSize(IN UINT _id)
        {
            return _group[_id].size();
        }

        /** Set the empty process to be finalize */
        VOID closeEmptyProcess()
        {
           for (UINT i = 0; i < _processNumber; ++i)
           {
               if (-1 == _processGroupId[i])
               {
                   _processGroupId[i] = -FINALIZE_GROUP_ID;
               }
           }
        }

        /** Finalize the process in group _gid */
        VOID closeGroup(IN UINT _gid)
        {
            if (_gid < 0 || _gid > _group.size())
            {
                return;
            }
            GROUP_TYPE::iterator _ite;
            for (_ite = _group[_gid].begin(); _group[_gid].end() != _ite; ++_ite)
            {
                _processGroupId[(*_ite)] = FINALIZE_GROUP_ID;
            }
        }

    private:

        INT *_processGroupId;
        UINT _processNumber;

        GROUP_LIST _group;

    public:

        static const INT EMPTY_GROUP_ID = -1;
        static const INT FINALIZE_GROUP_ID = -2;
    };

}; //namespace bcmi_frame

#endif //#ifndef _EASY_PARALLEL_GROUP_MANAGER_H